package cn.zmwh.im.server.netty.processor;

import cn.hutool.core.bean.BeanUtil;
import cn.zmwh.im.server.constant.BsKImConstant;
import cn.zmwh.im.server.constant.IMCmdConstants;
import cn.zmwh.im.server.constant.IMRedisKey;
import cn.zmwh.im.server.mq.dto.IMAuthInfo;
import cn.zmwh.im.server.mq.dto.IMInfo;
import cn.zmwh.im.server.mq.dto.LoginInfo;
import cn.zmwh.im.server.netty.ChannelUtil;
import cn.zmwh.im.server.netty.IMServerGroup;
import cn.zmwh.im.server.netty.UserChannelMap;
import cn.zmwh.im.server.utils.JwtUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component("loginProcessor")
@RequiredArgsConstructor
public class ProcessorLogin implements ImMessageProcessor {

    private final RedisTemplate redisTemplate;

    @Override
    public IMInfo read(ChannelHandlerContext ctx, IMInfo sendInfo) {
        Object data = sendInfo.getData();
        IMAuthInfo loginInfo = BeanUtil.toBean(data, IMAuthInfo.class);
        LoginInfo info = JwtUtil.getInfoFromToken(loginInfo.getAccessToken());
        if (!info.getEffectivity()) {
            IMInfo<Object> result = new IMInfo<>();
            result.setCmd(IMCmdConstants.FORCE_LOGOUT);
            String msg = info.getMsg();
            result.setData(msg);
            ctx.writeAndFlush(result);
            ChannelUtil.close(ctx.channel(), msg);
            log.warn("用户token校验不通过，强制下线,token:{}", loginInfo.getAccessToken());
            return null;
        }
        Long uid = info.getId();
        String terminal = info.getTerminal();
        log.info("用户登录，userId:{}", uid);
        Channel channel = UserChannelMap.getChannel(uid, terminal);
        if (channel != null && !ctx.channel().id().equals(channel.id())) {
            // 不允许多地登录,强制下线
            IMInfo<Object> logout = new IMInfo<>();
            logout.setCmd(IMCmdConstants.FORCE_LOGOUT);
            logout.setData("您已在其他地方登录，将被强制下线");
            ctx.writeAndFlush(logout);
            ChannelUtil.close(channel, "force_logout");
            log.info("异地登录，强制下线,userId:{}", uid);
        }
        // 绑定用户和channel
        UserChannelMap.addChannel(uid, terminal, ctx.channel());
        // 设置用户id属性
        AttributeKey<Long> userIdAttr = AttributeKey.valueOf(BsKImConstant.CHANNEL_ATTR_KEY.USER_ID);
        ctx.channel().attr(userIdAttr).set(uid);
        // 设置用户终端类型
        AttributeKey<String> terminalAttr = AttributeKey.valueOf(BsKImConstant.CHANNEL_ATTR_KEY.TERMINAL_TYPE);
        ctx.channel().attr(terminalAttr).set(terminal + "");
        // 初始化心跳次数
        AttributeKey<Long> heartBeatAttr = AttributeKey.valueOf(BsKImConstant.CHANNEL_ATTR_KEY.HEARTBEAT_TIMES);
        ctx.channel().attr(heartBeatAttr).set(0L);
        // 在redis上记录每个user的channelId，15秒没有心跳，则自动过期
        String key = IMRedisKey.GAIN_SERVER_ID + ":" + uid.toString() + ":" + terminal.toString();
        redisTemplate.opsForValue().set(key, IMServerGroup.serverId, BsKImConstant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS);
        // 响应ws
        IMInfo<Object> result = new IMInfo<>();
        result.setCmd(IMCmdConstants.LOGIN);
        //ctx.channel().writeAndFlush(result);
        return result;
    }

}
